package com.link.gateway.core.utils;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.link.gateway.base.interfacelog.model.InterfaceLog;
import com.link.gateway.base.urlinfo.model.UrlInfo;
import com.link.gateway.base.user.model.User;
import com.link.gateway.core.cllog.LCLogger;
import com.link.gateway.core.comproperty.InterfaceLogConstants;
import com.link.gateway.core.comproperty.ReqAndRespConstants;
import com.link.gateway.core.comproperty.TokenConstants;
import com.link.gateway.core.kafka.KafkaTemplateFacotry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;

import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
 * desc  多线程去插入接口日志
 *
 * @author libo
 * @date   2019-08-01
 * @param
 */
public class RecordInterfaceLogThread implements Runnable {
    private static final Logger logger = LogManager.getLogger(RecordInterfaceLogThread.class);
    private JSONObject logInfo;
    private ServerHttpRequest request;
    private ServerHttpResponse resp;
    private User user;
    private ServerWebExchange exchange;
    private String source = "";
    private String visitType = "";
    private String respBody = "";

    public User getUser() {
        return user;
    }

    /**
     * desc   线程里面接受参数
     *
     * @author libo
     * @date   2019-08-02
     * @param resp  ServerHttpResponse 实例
     * @param request ServerHttpRequest 实例
     * @param visitType  访问类型
     * @param source  来源
     */
    public RecordInterfaceLogThread(ServerHttpResponse resp, ServerHttpRequest request, String visitType,
                                    String source, User user, ServerWebExchange exchange) {
        this.resp = resp;
        this.request = request;
        this.visitType = visitType;
        this.source = source;
        this.user = user;
        this.exchange = exchange;
    }

    /**
     * desc   线程里面接受参数
     *
     * @author guoshan
     * @date   2019-01-10
     * @param exchange  ServerWebExchange 实例
     * @param request ServerHttpRequest 实例
     * @param visitType  访问类型
     * @param source  来源即token范围
     * @param user  用户信息
     * @param respBody 响应信息
     */
    public RecordInterfaceLogThread(ServerHttpRequest request, String visitType,
                                    String source, User user, ServerWebExchange exchange, String respBody) {
        this.request = request;
        this.visitType = visitType;
        this.source = source;
        this.user = user;
        this.exchange = exchange;
        this.respBody = respBody;
    }

    public String getVisitType() {
        return visitType;
    }

    public void setVisitType(String visitType) {
        this.visitType = visitType;
    }

    @Override
    public void run() {
        try {
            String requestUrl = exchange.getAttribute(ReqAndRespConstants.REQUEST_URL);
            String ipAddress = IpUtil.getIpAddress(request);
            //获取当前系统时间
            Long startTimes = exchange.getAttribute(ReqAndRespConstants.REQUEST_START_TIME_KEY);
            Map<String, UrlInfo> mapUrlDetail = CacheUtil.getAllUrlDetailFromCache(TokenConstants.ALL_URL_DETAIL_CACHE_KEY);
            UrlInfo urlInfo = mapUrlDetail.get(requestUrl);
            if (null == urlInfo) {
                //如果 urlInfo 为空，可能是因为当前的url用了通配符，那么基于通配符在遍历一遍
                //因为有通配符的接口不多，所以单独考虑
                AntPathMatcher antPathMatcher = new AntPathMatcher();
                for (Map.Entry<String, UrlInfo> map : mapUrlDetail.entrySet()) {
                    if (antPathMatcher.match(map.getKey(), requestUrl)) {
                        urlInfo = map.getValue();
                    }
                }
            }
            //获取接口日志信息
            InterfaceLog interfaceLog = setInterfaceLogModel(exchange, startTimes, urlInfo,
                    user, source, requestUrl, ipAddress);
            //将接口日志变为json字符串并传至kafka
            String interfaceLogStr = JSON.toJSONString(interfaceLog);
            KafkaTemplateFacotry.send(KafkaTemplateFacotry.FILTER_LINKLOG_TOPIC, interfaceLogStr);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * desc 根据接口的前端（URL列表）的配置来存日志的具体字段
     *
     * @author libo
     * @date   2019-08-07
     * @param exchange       ServerWebExchange对象
     * @param startTimes     开始调用接口的时间戳
     * @param urlInfo        当前接口的配置信息
     * @param user           当前调用接口人信息
     * @param source         来源
     * @param requestUrl     请求url
     * @param ipAddress      请求发出所在机器的IP地址
     */
    private InterfaceLog setInterfaceLogModel(ServerWebExchange exchange, Long startTimes, UrlInfo urlInfo, User user, String source,
                                              String requestUrl, String ipAddress) {
        String inputParaFlag = (urlInfo == null ? "Y" : urlInfo.getInputParaFlag());
        String outParaFlag = (urlInfo == null ? "Y" : urlInfo.getOutParaFlag());
        int logKeepDay = (urlInfo == null ? 30 : urlInfo.getLogKeepTime());
        String requestStr = "";
        if (StringUtils.isNotBlank(inputParaFlag) && "Y".equals(inputParaFlag)) {
            try {
                requestStr = RequestDataUtils.getReqDataStr(exchange);
            } catch (UnsupportedEncodingException e) {
                logger.error(e.getMessage());
            }
        }
      /*  if ("N".equals(outParaFlag)) {
            respBody = "";
        }*/

        //如果记录响应体，并且发生异常，则记录异常信息
        InterfaceLog interfaceLog = new InterfaceLog();
        boolean isLoginUrl = (urlInfo != null && "/base/user/login".equals(urlInfo.getUrl()));
        boolean isRecordRespFlag = "Y".equalsIgnoreCase(outParaFlag);
        try {
            JSONObject jsonObject = JSONObject.parseObject(respBody);
            if (isLoginUrl) {
                JSONObject joDTO = (JSONObject) jsonObject.get("respDTO");
                String loginCode = joDTO.getString("code");
                if ("-1".equals(loginCode)) {
                    this.visitType = "Over";
                    interfaceLog.setProcessStatus("Fail");
                } else {
                    interfaceLog.setProcessStatus("Success");
                }

            } else {
                String success = jsonObject.getString("success");
                if ("false".equals(success)) {
                    interfaceLog.setProcessStatus("Fail");
                    interfaceLog.setErrMsg(jsonObject.getString("result"));
                } else {
                    interfaceLog.setProcessStatus("Success");
                }
            }
        } catch (Exception e) {
            LCLogger.withException(e.getMessage());
        }
        //当token无效时获取不到用户，此时需要判断再塞值
        if (null != user) {
            /**帐套*/
            interfaceLog.setCorpId(user.getCorpid());
            /**最后更新用户id*/
            interfaceLog.setLastUpdBy(user.getId());
            /**创建用户id*/
            interfaceLog.setCreatedBy(user.getId());
            /**组织id*/
            interfaceLog.setOrgId(user.getOrgId());
            /**职位id*/
            interfaceLog.setPostnId(user.getPostnId());
            /**用户名/工号*/
            interfaceLog.setUserName(user.getUsername());
            /**姓名*/
            interfaceLog.setUserFirstName(user.getFirstName());
            /**客户端id*/
            interfaceLog.setClientId(user.getCurClientId());
            /**客户端名称*/
            interfaceLog.setClientName(user.getCurClientName());
        }
        /**来源*/
        interfaceLog.setSource(source);
        /**访问类型*/
        if (!InterfaceLogConstants.NORMAL.equals(visitType) && !InterfaceLogConstants.DATA_CHANGE.equals(visitType)) {
            interfaceLog.setVisitType(InterfaceLogConstants.PERMISSION_OVER);
        } else {
            interfaceLog.setVisitType(visitType);
        }
        interfaceLog.setOverPermType(visitType);
        /**接口地址*/
        interfaceLog.setUrl(requestUrl);
        /**输入参数*/
        interfaceLog.setRequestBody(requestStr);
        /**输出参数 */
        if (isRecordRespFlag) {
            interfaceLog.setResponseBody(respBody);
        }
        /**ip地址*/
        interfaceLog.setIp(ipAddress);
        //开始时间（时间戳）
        interfaceLog.setStartTime(startTimes);
        //结束时间
        long endTime = System.currentTimeMillis();
        interfaceLog.setEndTime(endTime);

        double consumeTime = FunctionTimeUtil.div((endTime - startTimes), 1000, 3);
        interfaceLog.setConsumeTime(consumeTime);
        interfaceLog.setLogKeepDay(logKeepDay);
        return interfaceLog;
    }
}
